//CalculatorServer.hpp
#pragma once
#include "Sock.hpp"
#include <pthread.h>
#include <functional>
#include "Protocol.hpp"

using func_t = function<Response(const Request &)>;//和typedef一样的效果，是为了业务处理函数的
class CalculatorServer;

//此类是为了后续创建线程和客户端进行通信时所需要的
class ThreadData
{
public:
    ThreadData(string clientip, uint16_t clientport, CalculatorServer *server, int sock)
        : _clientip(clientip),
          _clientport(clientport),
          _server(server), _sock(sock)
    {}

    string _clientip;//客户端的IP
    uint16_t _clientport;//客户端的端口
    CalculatorServer *_server;//方便用于指向服务器类中和客户端通信的ServerIO
    int _sock;//通信用的套接字
};

class CalculatorServer
{
public:
    //构造
    CalculatorServer(uint16_t serverport, func_t func)
        : _serverport(serverport), _func(func)
    {}

    //初始化
    void Init()
    {
        //创建套接字
        _listensock.Socket();
        //绑定IP和port
        _listensock.Bind(_serverport);
        //开始监听
        _listensock.Listen();
        LogMessage(Information, "init server done,listensock:%d", _listensock.GetSock());
    }

    void Start()
    {
        while (1)
        {
            string clientip;
            uint16_t clientport;
            //sock是真正用来通信的套接字
            int sock = _listensock.Accept(clientip, clientport);
            if (sock < 0)
            {
                continue;
            }
            LogMessage(Debug, "get a new client,client information:[%s:%d]", clientip.c_str(), clientport);
         
            //创建线程，交给线程去完成真正的与客户端通信
            pthread_t tid;
            ThreadData *data = new ThreadData(clientip, clientport, this, sock);
            pthread_create(&tid, nullptr, ThreadRoutine, data);//通过ThreadRoutine来调用真正通信函数
            LogMessage(Debug,"create pthread success");
        }
    }

    //套了一层
    static void *ThreadRoutine(void *arg)
    {
        //线程分离，不需要主线程去等待回收
        pthread_detach(pthread_self());
        ThreadData *data = static_cast<ThreadData *>(arg);
        //调用真正通信的函数
        data->_server->ServerIO(data->_clientip, data->_clientport, data->_sock);
        LogMessage(Information,"thread quit,client quit");
        delete data;
        return nullptr;
    }

    //真正和客户端开始通信
     void ServerIO(string clientip, uint16_t clientport, int sock)
    {

        //接收到的报文不一定是完整的，因此需要有一个区域存储所有的报文
        string storage_packaging;
        while (1)
        {
            LogMessage(Debug,"server start");
            string packaging;//存储获取到的完整封装报文->封装是应用层对于报头+有效载荷的称呼
            // 1.确保读到的是完整的字符串报文
            // 7\t\n10 + 20\t\n
            int packloadlen= ReadPackage(sock, storage_packaging, packaging);//payloadlen是有效载荷的长度
            if (packloadlen== 0)
            {
                //客户端关闭了
                LogMessage(Warning, "read fail,the client already close");
                return;
            }
            else if (packloadlen < 0)
            {
                //获取失败
                LogMessage(Information, "analysis fail,try again");
                continue;
            }
            else
            {
                // 2.去掉报头
                string payload = DelHeader(packaging, packloadlen);
                //3.反序列化
                Request req;
                if(!req.Deserialization(payload))
                {
                    cout<<"反序列化失败"<<endl;
                }
                // 4.处理业务
                Response res = _func(req);
                // 5.给用户返回响应,将数据序列化
                string sed;
                res.Serialize(sed);
                // 6.添加报头
                string info=AddHeader(sed);
                //7.发送
                send(sock,info.c_str(),info.size(),0);
            }
        }
    }



    Sock _listensock;//用于socket套接字的类对象
    uint16_t _serverport;//服务器的端口号
    func_t _func;//业务处理接口
};